#include "slice.h"

#include <string.h>

Slice SliceCreate(int capacity) {
  SliceStruct* ss = (SliceStruct *)malloc(sizeof(SliceStruct) + sizeof(char) * (capacity + 1));
  ss->capacity = capacity;
  ss->length   = 0;
  ss->data[0]  = '\0';
  return ss->data;
}

Slice SliceCreate2(const char* data, int length) {
  SliceStruct* ss = (SliceStruct *)malloc(sizeof(SliceStruct) + sizeof(char) * (length + 1));
  ss->capacity = length;
  ss->length = length;
  memcpy(ss->data, data, length);
  ss->data[length] = '\0';
  return ss->data;
}

void SliceDestroy(void* data) {
  if (data) {
    Slice slice = (Slice)data;
    SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
    free(ss);
  }
}

void SliceEmpty(Slice slice) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  ss->data[0] = '\0';
  ss->length = 0;
}

int SliceIsEmpty(Slice slice) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  return ss->length == 0;
}

int SliceLength(Slice slice) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  return ss->length;
}

int SliceCapacity(Slice slice) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  return ss->capacity;
}

Slice SliceResize(Slice slice, int capacity) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  if (capacity > ss->capacity) {
    ss = (SliceStruct *)realloc(ss, sizeof(SliceStruct) + sizeof(char) * (capacity + 1));
    ss->capacity = capacity;
  }
  return ss->data;
}

Slice SliceClone(const Slice slice) {
  int length = SliceLength(slice);
  Slice dst = SliceCreate(length);
  memcpy(dst, slice, length);
  dst[length] = '\0';
  SliceStruct* ss = (SliceStruct *)(dst - sizeof(SliceStruct)); 
  ss->length = length;
  return dst;
}

void SliceCopy(Slice slice, const char* b, int length) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  memcpy(slice, b, length);
  slice[length] = '\0';
  ss->length = length;
}

int SlicePrint(Slice slice, const char* format, ...) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  va_list ap;
  va_start(ap, format);
  ss->length = vsnprintf(slice, ss->capacity, format, ap); 
  va_end(ap);
  return ss->length;
}

int SliceCat(Slice slice, const char* str, int length) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  memcpy(ss->data + ss->length, str, length);
  ss->length += length;
  ss->data[ss->length] = '\0';
  return ss->length;
}

int SliceCompare(const Slice a, const Slice b) {
  SliceStruct* aa = (SliceStruct *)(a - sizeof(SliceStruct)); 
  SliceStruct* bb = (SliceStruct *)(b - sizeof(SliceStruct)); 
  int length = aa->length > bb->length ? bb->length : aa->length;
  int s = memcmp(aa->data, bb->data, length);
  if (a == 0) return aa->length > bb->length ? 1 : -1;
  return s;
}

uint32_t SliceHash(const Slice slice) {
  SliceStruct* ss = (SliceStruct *)(slice - sizeof(SliceStruct)); 
  uint32_t x = 0;
  for (int i = 0; i < ss->length; i++) {
    x = x * 33 + ss->data[i];
  }
  return x;
}

